package PrzestrzenCiagla;

import Zbiory.Element;
import Zbiory.Zbior;
import FunkcjePrzynaleznosci.IFunkcjaPrzynaleznosci;
import Narzedzia.CalkowanieNumeryczne;

public class CiaglyZbiorRozmyty implements Zbior {

	private PrzestrzenCiagla przestrzen;
	private IFunkcjaPrzynaleznosci funkcjaPrzynaleznosci;

	public CiaglyZbiorRozmyty(PrzestrzenCiagla przestrzen, IFunkcjaPrzynaleznosci funkcjaPrzynaleznosci) {
		super();
		this.przestrzen = przestrzen;
		this.funkcjaPrzynaleznosci = funkcjaPrzynaleznosci;
	}

	public PrzestrzenCiagla getPrzestrzen() {
		return przestrzen;
	}

	public IFunkcjaPrzynaleznosci getFunkcjaPrzynaleznosci() {
		return funkcjaPrzynaleznosci;
	}

	public float getPrzynaleznosc(float x) {
		return funkcjaPrzynaleznosci.getWartosc(x);
	}

	public boolean czyPusty() {

		for (float x = getPrzestrzen().getPoczatek(); x <= getPrzestrzen().getKoniec(); x += getPrzestrzen().getKrok()) {
			if (getPrzynaleznosc(x) > 0) {
				return false;
			}
		}
		return true;
	}

	public boolean czyWypukly() {
		for (float alfa = 0.0f; alfa < 1.0f; alfa += getPrzestrzen().getKrok()) {
			CiaglyZbiorRozmyty alfaPrzekroj = new AlfaPrzekrojCiaglyZbiorRozmyty(this, alfa);
			if (czyZbiorWypukly(alfaPrzekroj) == false) {
				return false;
			}
		}
		return true;
	}

	private boolean czyZbiorWypukly(CiaglyZbiorRozmyty zbior) {
		float poczatek = zbior.poczatekNiezerowychPrzynaleznosci();
		float koniec = zbior.koniecNiezerowychPrzynaleznosci();
		for (float x = poczatek; x <= koniec; x += zbior.getPrzestrzen().getKrok()) {
			if (zbior.getPrzynaleznosc(x) < 1.0f) {
				return false;
			}
		}
		return true;
	}

	public boolean czyWklesly() {
		return !czyWypukly();
	}

	public boolean czyNormalny() {
		return getWysokosc() >= 1.0f;
	}

	public float getWysokosc() {
		float wysokosc = 0.0f;
		for (float x = getPrzestrzen().getPoczatek(); x <= getPrzestrzen().getKoniec(); x += getPrzestrzen().getKrok()) {
			wysokosc = Math.max(getPrzynaleznosc(x), wysokosc);
		}
		return wysokosc;
	}

	@Override
	public float getPrzynaleznosc(Element element) {
		return getPrzynaleznosc(element.getWartosc());
	}

	public float poczatekNiezerowychPrzynaleznosci() {
		for (float x = getPrzestrzen().getPoczatek(); x <= getPrzestrzen().getKoniec(); x += getPrzestrzen().getKrok()) {
			if (getPrzynaleznosc(x) > 0.0f) {
				return x;
			}
		}
		throw new IllegalStateException("Zbior jest pusty");
	}

	public float koniecNiezerowychPrzynaleznosci() {
		for (float x = getPrzestrzen().getKoniec(); x >= getPrzestrzen().getPoczatek(); x -= getPrzestrzen().getKrok()) {
			if (getPrzynaleznosc(x) > 0.0f) {
				return x;
			}
		}
		throw new IllegalStateException("Zbior jest pusty");
	}
	
	public float dlugoscNosnika(){
		return koniecNiezerowychPrzynaleznosci() - poczatekNiezerowychPrzynaleznosci();
	}
	
	public float getClm(){
		return CalkowanieNumeryczne.metodaTrapezowa(this);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((funkcjaPrzynaleznosci == null) ? 0 : funkcjaPrzynaleznosci.hashCode());
		result = prime * result + ((przestrzen == null) ? 0 : przestrzen.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CiaglyZbiorRozmyty other = (CiaglyZbiorRozmyty) obj;
		if (funkcjaPrzynaleznosci == null) {
			if (other.funkcjaPrzynaleznosci != null)
				return false;
		} else if (!funkcjaPrzynaleznosci.equals(other.funkcjaPrzynaleznosci))
			return false;
		if (przestrzen == null) {
			if (other.przestrzen != null)
				return false;
		} else if (!przestrzen.equals(other.przestrzen))
			return false;
		return true;
	}
	
	

}
